﻿using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using ProphetsWay.myMd5.Core;

namespace ProphetsWay.myMd5.Win
{
	public partial class MyMd5 : Form
	{
		public MyMd5()
		{
			InitializeComponent();

			dlgFile.FileName = "";
			dlgFile.Multiselect = false;
			dlgFile.CheckFileExists = true;
			lblStatus.Text = OPEN_FILE_MESSAGE;
			_defaultColor = tbOutput.BackColor;
			timer.Interval = 350;
			timer.Tick += TimerTick;
		}

		private void TimerTick(object sender, EventArgs e)
		{
			if (!_asyncWorking)
				timer.Stop();
			else
			{
				if (_asyncTick == long.MaxValue)
					_asyncTick = 0;

				var dots = new StringBuilder();
				var numOfDots = (_asyncTick%3) + 1;
				for (var i = 0; i < numOfDots; i++)
					dots.Append(".");

				_asyncTick++;

				SetText(string.Format(@"Working{0}", dots), lblStatus);
			}
		}


		private const string OPEN_FILE_MESSAGE = @"Enter the file name in the upper text box, or click ""Browse"" to select the file to calculate it's MD5 checksum.   You can optionally enter its Expected Value in the field provided for computed comparison.";
		private const string SET_OR_GET_MD5 = @"Enter your expected MD5 checksum into the field provided, or click ""Get MD5 Checksum"" to calculate the MD5 of the file selected.";
		private const string ERROR_GEN_MD5 = @"There was an unknown error when trying to generate the MD5 for the file you've chosen.  Please try again later.";
	
		private const string GENERATE_SUCCESS = @"MD5 successfully generated and value is below.";
		private const string GENERATE_SUCCESS_VALID = @"MD5 successfully generated and value is below.  Comparison shows that it is equal to the expected result.";
		private const string GENERATE_SUCCESS_INVALID = @"MD5 successfully generated and value is below.  Comparison shows that it is different to the expected result.";
	
		private readonly Color _defaultColor;

		private void BtnBrowseClick(object sender, EventArgs e)
		{
			var rslt = dlgFile.ShowDialog();

			switch(rslt)
			{
				case DialogResult.OK:
					tbInputFile.Text = dlgFile.FileName;
					lblStatus.Text = SET_OR_GET_MD5;
					break;

				default:
					tbInputFile.Text = string.Empty;

					lblStatus.Text = OPEN_FILE_MESSAGE;
					break;
			}
		}

		private void TbInputFileTextChanged(object sender, EventArgs e)
		{
			SetText(string.Empty, tbOutput);
			SetBackColor(_defaultColor, tbOutput);

			if(!string.IsNullOrEmpty(tbInputFile.Text))
			{
				try
				{
					if (File.Exists(tbInputFile.Text)) 
					{
						SetText(SET_OR_GET_MD5, lblStatus);
						SetEnabled(true, btnExecute);
					}
					else
					{
						SetText(OPEN_FILE_MESSAGE, lblStatus);
						SetEnabled(false, btnExecute);
					}
				}
				catch
				{
					SetText(OPEN_FILE_MESSAGE, lblStatus);
					SetEnabled(false, btnExecute);
				}
			}
		}

		private void BtnCloseClick(object sender, EventArgs e)
		{
			Close();
		}

		private void BtnExecuteClick(object sender, EventArgs e)
		{
			btnExecute.Enabled = false;
			lblStatus.Text = @"Working...";
			tbOutput.BackColor = _defaultColor;

			_asyncWorking = true;
			_asyncTick = 0;

			var th = new Thread(GenerateMp5);
			th.Start(tbInputFile.Text);
			timer.Start();
		}

		private static bool _asyncWorking;
		private static long _asyncTick;

		private void GenerateMp5(object mp5Args)
		{
			var fileName = mp5Args.ToString();

			try
			{
				var gen = new Md5Utilities();
				var fileMd5 = gen.GenerateMd5(fileName);

				SetText(fileMd5, tbOutput);
				SetEnabled(true, btnExecute);
			}
			catch
			{
				MessageBox.Show(ERROR_GEN_MD5);
				SetEnabled(true, btnExecute);
				return;
			}
			finally
			{
				CompareMp5AndReport();

				_asyncWorking = false;
			}
			

		}

		private void CompareMp5AndReport()
		{
			if (string.IsNullOrEmpty(tbInputMd5.Text))
			{
				SetText(GENERATE_SUCCESS, lblStatus);
			}
			else
			{
				if (string.Equals(tbOutput.Text, tbInputMd5.Text))
				{
					SetText(GENERATE_SUCCESS_VALID, lblStatus);
					SetBackColor(Color.LightGreen, tbOutput);
				}
				else
				{
					SetText(GENERATE_SUCCESS_INVALID, lblStatus);
					SetBackColor(Color.Pink, tbOutput);
				}
			}
		}


#region Delegate Methods

		private delegate void SetTextCallback(string text, Control ctrl);
		private void SetText(string text, Control ctrl)
		{
			if (ctrl.InvokeRequired)
			{
				var d = new SetTextCallback(SetText);
				Invoke(d, new object[] { text, ctrl });
			}
			else
			{
				ctrl.Text = text;
			}
		}

		private delegate void SetBackColorCallback(Color color, Control ctrl);
		private void SetBackColor(Color color, Control ctrl)
		{
			if (ctrl.InvokeRequired)
			{
				var d = new SetBackColorCallback(SetBackColor);
				Invoke(d, new object[] { color, ctrl });
			}
			else
			{
				ctrl.BackColor = color;
			}
		}

		private delegate void SetEnabledCallback(bool state, Control ctrl);
		private void SetEnabled(bool state, Control ctrl)
		{
			if(ctrl.InvokeRequired)
			{
				var d = new SetEnabledCallback(SetEnabled);
				Invoke(d, new object[] {state, ctrl});
			}
			else
			{
				ctrl.Enabled = state;
			}
		}

#endregion



	

	}
}
